venv+VS Codeでプロンプトが変な状態になったときの修復法
はじめに
VS Codeのターミナル+venvでPythonの仮想環境を作る際に、特定条件下でプロンプトが変な状態になることがあります。普通に困ったので備忘録として記録しておきます。
再現を確認できたのは、以下の環境です。
OS | VS Code version | Python version |
---|---|---|
macOS Sonoma14.5 | 1.89.0 (Universal) | Python 3.12.3 |
変な状態ってなによ
再現手順 (修復できますが、自己責任でお願いします。)
- 普通にvenv環境を作る
- VS Codeのターミナル上でsource activateして仮想環境を有効化 (行頭に(環境名)が付きます)
- いったんVS Codeのウインドウを×で閉じる
- VS Codeを開き直す
- ターミナルの履歴が復元された場合、venvの仮想環境が有効になったままだが、この状態でdeactivateが実行できない。
- PATHとかもズレたままになるので詰む
(venv) user sample_app % deactivate (venv) user sample_app %
最終的な状況はこんな感じになります。表示上は仮想環境にいるのにdeactivateは使えません。エラーが出ることもあれば出ないこともある気がします。 裏側で何が行われているのか、次の節で調べてみます。お急ぎの方は読み飛ばしてください。
状況
activateは簡単にいうとこんなことをやっています。
1.deactivate関数を作る
deactivate () { if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then PATH="${_OLD_VIRTUAL_PATH:-}" export PATH unset _OLD_VIRTUAL_PATH fi if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" export PYTHONHOME unset _OLD_VIRTUAL_PYTHONHOME fi hash -r 2> /dev/null if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then PS1="${_OLD_VIRTUAL_PS1:-}" export PS1 unset _OLD_VIRTUAL_PS1 fi unset VIRTUAL_ENV unset VIRTUAL_ENV_PROMPT if [ ! "${1:-}" = "nondestructive" ] ; then unset -f deactivate fi }
この関数は後述する各環境変数の変更を元に戻します。
2.deactivateする
deactivate nondestructive
すでにvenv環境が有効ならdeactivateします。ただし、nondestructiveを引数に与えているのでdeactivate関数自体は破棄しません。
3.環境変数を上書きする
if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then export VIRTUAL_ENV=$(cygpath "/Users/user/sample_app") else export VIRTUAL_ENV="/Users/user/sample_app" fi _OLD_VIRTUAL_PATH="$PATH" PATH="$VIRTUAL_ENV/bin:$PATH"i export PATH if [ -n "${PYTHONHOME:-}" ] ; then _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" unset PYTHONHOME fi if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then _OLD_VIRTUAL_PS1="${PS1:-}" PS1="(sample_app) ${PS1:-}" export PS1 VIRTUAL_ENV_PROMPT="(sample_app) " export VIRTUAL_ENV_PROMPT fi hash -r 2> /dev/null
ここでやっていることは、
- $PATHをバックアップの上あらかじめ定義されているもので置き換え
- $PYTHONHOMEをバックアップの上削除
- $PS1に(環境名) を付ける
ほかにもいろいろやってますが、今回影響してくるのはここら辺かなと思います。$PYTHONHOMEに関しては、そもそも値が入っていないこともあります。
で、今回の変な状況というのがどういう状態になっているかというと、
- activateでPATHとPS1がバックアップ&上書きされる
- VS Codeを×で閉じて履歴が復元されると、exportした環境変数が消えない!!
- exportされた上書き後のPS1などは残っているのに、元の_OLD_xxxが消えてしまっているので、deactivate内のif文に引っかからず実行できない。
という感じっぽいです。困った。。。
解決方法
解決方法はとても簡単です。影響が出ている環境変数が少なくとも、
- $PATH
- $PS1
であることがコードから自明です。人によっては$PYTHONHOMEも。
そのため、別のターミナルなどで上の環境変数をechoし、これで上書きすればOKです!。頻発する場合はzshrcとかで対応してもいいと思います。
終わりに
deactivateせずに閉じちゃったりすると引っかかることがあるので結構厄介な気がしています。